﻿#include <iostream>
#include <fstream>
#include <ctime>
#include <cstdlib>
#include <vector>
#include <queue>
#include <string>
#include <algorithm>
#include <locale>//本地化，方便写中文到文件

// 定义个体结构体，包含身份证号、年龄、性别等信息
struct Person {
    int id;
    int age;
    std::string gender;
public:
    virtual void PrintPerInfo(std::ostream& os) {
        os << "------------------------\n";
        os << "当前就诊人：" << std::endl;
        os << "身份： " << "普通" << std::endl;
        os << "ID： " << id << std::endl;
        os << "年龄： " << age << std::endl;
        os << "性别： " << gender << std::endl;
    }
};

// 定义警察结构体，继承自个体结构体，额外包含警察身份证号信息
struct Police : public Person {
    int policeId;
public:
    virtual void PrintPerInfo(std::ostream& os) override {
        os << "------------------------\n";
        os << "当前就诊人：" << std::endl;
        os << "身份： " << "警察" << std::endl;
        os << "ID： " << id << std::endl;
        os << "年龄： " << age << std::endl;
        os << "性别： " << gender << std::endl;
        os << "警号： " << policeId << std::endl;
    }
};

// 核酸采集点类
template <class T>
class CollectionPoint {
private:
    std::queue<T> queue;
    int collectionSpeed;
public:
    CollectionPoint(int speed = 5) : collectionSpeed(speed) {}
    void addPerson(const T& p) {
        queue.push(p);
    }


    void process(std::ostream& os) {
        for (int i = 0; i < collectionSpeed && !queue.empty(); ++i) {
            T* cur = &queue.front(); //必须是基类的指针或引⽤
            cur->PrintPerInfo(os);
            queue.pop();
        }
    }
    int getQueueSize() const {
        return queue.size();
    }
};


//public继承的⼦类对象 可以赋值给 ⽗类的对象 / ⽗类的指针 / ⽗类的引⽤。有个形象的说法叫
//切⽚，即⼦类中⽗类那部分切来赋值过去。





// 核酸采集站类
class CollectionStation {
private:
    std::vector<CollectionPoint<Person>> regularPoints;
    CollectionPoint<Police> policePoint;
    std::ofstream outputFile;
public:
    CollectionStation() {
        regularPoints.push_back(CollectionPoint<Person>());
        outputFile.open("collection_data.txt");
        if (!outputFile) {
            std::cerr << "Error opening output file!" << std::endl;
            // 可以在这里根据具体需求决定是否抛出异常让程序终止，或者尝试其他处理方式，比如提示用户手动处理文件问题后重新运行等
            // 例如，可以抛出一个自定义异常
            //这样当文件打开失败时，程序能及时给出错误提示，避免后续因文件操作导致的不可预测错误，保证程序执行逻辑的正确性。
            throw std::runtime_error("Output file cannot be opened.");
        }
    }
  //  追加模式：使用ios::app模式可以在文件末尾追加内容，而不会截断文件。例如：
   //     std::ofstream outFile("example.txt", std::ios::app);

    ~CollectionStation() {
        outputFile.close();
    }
    void simulate(int minutes) {
        srand(static_cast<unsigned int>(time(nullptr)));
        for (int minute = 1; minute <= minutes; ++minute) {
            int numPeople = rand() % 41 + 10;  // 每分钟来的人数范围10-50
            std::vector<Person> people;
            std::vector<Police> police;
            int numPolice = numPeople/2;  // 警察占比1/11
            int numRegular = numPeople - numPolice;  // 普通人数
            // 生成普通个体信息
            for (int i = 0; i < numRegular; ++i) {
                Person p;
                p.id = rand() % 100001 + 100000;
                p.age = rand() % 150 + 1;
                p.gender = (rand() % 2 == 0) ? "Female" : "Male";
                people.push_back(p);
            }
            // 生成警察个体信息
            for (int i = 0; i < numPolice; ++i) {
                Police p;
                p.id = rand() % 1001 + 1000;
                p.age = rand() % 150 + 1;
                p.gender = (rand() % 2 == 0) ? "Female" : "Male";
                p.policeId = rand() % 1001 + 1000;
                police.push_back(p);
            }
            // 分配人员到采集点
            assignPeople(people);
            assignPolice(police);
            // 处理采集点队列
            processPoints();
            // 输出并记录采集点队列信息
            outputQueueInfo(minute);
        }
    }
private:
    void assignPeople(const std::vector<Person>& people) {
        for (const auto& p : people) {
            // 找排队人数最少的队
            int minQueueSize = regularPoints[0].getQueueSize();
            size_t minIndex = 0;
            for (size_t i = 1; i < regularPoints.size(); ++i) {
                int currentQueueSize = regularPoints[i].getQueueSize();
                if (currentQueueSize < minQueueSize) {
                    minQueueSize = currentQueueSize;
                    minIndex = i;
                }
            }
            //向最少人的队里面加人
            regularPoints[minIndex].addPerson(p);
            // 如果分配后该采集点队列达到30人，则新增一个常规采集点
            if (regularPoints[minIndex].getQueueSize() == 30) {
                regularPoints.push_back(CollectionPoint<Person>());
            }
        }
    }
    void assignPolice(const std::vector<Police>& police) {
        for (const auto& p : police) {
            policePoint.addPerson(p);
        }
    }

    
    void processPoints() {
        for (auto& point : regularPoints) {
            point.process(outputFile);  // 将文件输出流传入，以便信息写入文件
            point.process(std::cout);
        }
        policePoint.process(outputFile);
        policePoint.process(std::cout);
    }


    void outputQueueInfo(int minute) {
        std::cout << "Minute " << minute << ":\n";
        outputFile << "Minute " << minute << ":\n";
        std::cout << "Regular Collection Points:\n";
        outputFile << "Regular Collection Points:\n";
        for (size_t i = 0; i < regularPoints.size(); ++i) {
            std::cout << "Point " << i << " Queue Size: " << regularPoints[i].getQueueSize() << "\n";
            outputFile << "Point " << i << " Queue Size: " << regularPoints[i].getQueueSize() << "\n";
        }
        std::cout << "Police Collection Point Queue Size: " << policePoint.getQueueSize() << "\n";
        outputFile << "Police Collection Point Queue Size: " << policePoint.getQueueSize() << "\n";
        std::cout << "------------------------\n";
        outputFile << "------------------------\n";
    }
};

int main() {
    std::locale::global(std::locale(""));
    CollectionStation station;
    station.simulate(2);
    return 0;
}



//抛异常
//#include <iostream>
//#include <exception>
//int main() {
//try {
//    int num1 = 10;
//    int num2 = 0;
//    if (num2 == 0) {
//        throw std::runtime_error("除数不能为零");
//    }
//    int result = num1 / num2;
//    std::cout << "结果: " << result << std::endl;
//}
//catch (const std::runtime_error& e) {
//    std::cerr << "发生异常: " << e.what() << std::endl;
//}
//return 0;
//}